package net.lab1024.sa.admin.module.business.category.controller;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.common.Log;
import net.lab1024.sa.admin.constant.AdminSwaggerTagConst;
import net.lab1024.sa.admin.module.business.category.domain.dto.OperationLogDTO;
import net.lab1024.sa.admin.module.business.category.domain.dto.OperationLogExportDTO;
import net.lab1024.sa.admin.module.business.category.domain.entity.LogQuery;
import net.lab1024.sa.admin.module.business.category.domain.entity.OperationLog;
import net.lab1024.sa.admin.module.business.category.service.OperationLogService;
import net.lab1024.sa.base.common.exception.BusinessException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Tag(name = AdminSwaggerTagConst.Business.SYNTHESIS_OPERATE_LOG)
@RestController
@RequestMapping("/api/logs/")
@RequiredArgsConstructor
@Slf4j
public class OperationLogController {
    private final OperationLogService logService;

    @Operation(summary = "查询操作日志（分页）")
    @PostMapping("list")
    public Page<OperationLogDTO> searchLogs(@RequestBody LogQuery query) {
        Page<OperationLogDTO> page = logService.listLogs(query);
        return page;
    }

    @Log(module = "日志管理", operation = "导出操作日志")
    @Operation(summary = "导出操作日志（Excel）")
    @PostMapping("export")
    public void exportLogs(@RequestBody LogQuery query, HttpServletResponse response) {
        try {
            // 1. 获取数据
            List<OperationLog> logs = logService.listAllLogs(query);

            // 2. 转换数据格式
            List<OperationLogExportDTO> exportData = IntStream.range(0, logs.size())
                    .mapToObj(i -> new OperationLogExportDTO(i + 1, logs.get(i)))
                    .collect(Collectors.toList());

            // 3. 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");

            // 文件名处理中文和空格
            String fileName = "操作日志_" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");

            response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 4. 导出Excel
            OutputStream outputStream = response.getOutputStream();
            EasyExcel.write(outputStream, OperationLogExportDTO.class)
                    .sheet("操作日志")
                    .doWrite(exportData);

        } catch (IOException e) {
            log.error("导出操作日志失败", e);
            handleExportError(response, "导出操作日志失败: " + e.getMessage());
        }
    }

    // 专用错误处理方法
    private void handleExportError(HttpServletResponse response, String errorMsg) {
        try {
            if (!response.isCommitted()) { // 确保响应未提交
                response.reset(); // 重置响应
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

                // 统一使用OutputStream写入错误信息
                OutputStream out = response.getOutputStream();
                out.write(("{\"code\":500,\"message\":\"" + errorMsg + "\"}").getBytes());
                out.flush();
            }
        } catch (IOException ex) {
            log.error("写入错误信息失败", ex);
        }
    }
}